package top.wshape1.rpc.consumer.tolerant;

import lombok.extern.slf4j.Slf4j;
import top.wshape1.rpc.common.entity.ServiceMeta;
import top.wshape1.rpc.config.JJRpcConfig;

import java.util.function.Function;

/**
 * @author Wshape1
 * @version 1.0
 * @description 失败重试策略
 * @since 2024-02-16
 */

@Slf4j
public class FailbackTolerantStrategy implements FaultTolerantStrategy {

    private final int retryTimes;

    private final int retryInterval;

    public FailbackTolerantStrategy() {
        this.retryTimes = JJRpcConfig.CONFIG.getConsumer().getFaultTolerant().getRetryTimes();
        this.retryInterval = JJRpcConfig.CONFIG.getConsumer().getFaultTolerant().getRetryInterval();
    }

    @Override
    public Object handle(Function<ServiceMeta, Object> invoker, ServiceMeta curServiceMeta, Exception error) {
        log.info("Failback. currentServiceMeta: {}, error: {}", curServiceMeta, error.getMessage());
        for (int i = 0; i < retryTimes; i++) {
            try {
                return invoker.apply(curServiceMeta);
            } catch (Exception e) {
                log.warn("invoke failed. retry times: {}/{}, error: {}", i + 1, retryTimes, e.getMessage());
                error = e;

                long left = retryInterval;
                while (left > 0) {
                    long start = System.currentTimeMillis();
                    try {
                        Thread.sleep(left);
                    } catch (InterruptedException ignored) {
                    } finally {
                        left -= (System.currentTimeMillis() - start);
                    }
                }
            }
        }
        throw new RuntimeException(error);
    }
}
